package com.jsb.gatewayservice;

import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBufAllocator;
import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static java.util.Objects.isNull;

//@RefreshScope
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthorizeFilter.class);
    /**
     * id标识
     */
    private static final String ID = "uid";

    /**
     * 放行的请求路径
     */
//    @Value("${jsb.authorization.whiteList}")
    private final String[] skipAuthUrls = new String[]{
            "/userApi/order/userOrder/userBuyInfo",
            "/userApi/user/mini/login",
            "/userApi/user/laundryV1/getIndexDataV1",
            "/userApi/product/userProduct/findAllCateAndGoods",
            "/userApi/user/userInfo/getList",
            "/userApi/order/coupon/getUserBalanceAndCoupon",
            "/userApi/order/coupon/getUserCouponBuyEffective",
            "/userApi/order/coupon/vipCenterPage",
            "/userApi/user/laundryV2/getIndexData",
            "/userApi/user/laundryV1/promotion/count",
            "/userApi/product/userProduct/searchByClothesTitle",
            "/userApi/order/jsbUserCallBack",
            "/userApi/product/userProduct/rotationChart",
            "/adminApi/admin/laundryFactory/login",
            "/adminApi/admin/laundryFactory/categoryImg",

            "/adminApi/admin/laundryShops/login",
            "/adminApi/admin/laundryShops/verCode",


            "/userApi/user/app/login",
            "/userApi/user/app/verCode",
//            "/userApi/user",

            "/riderOrder", "/riderInfo"

    };

    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        LOGGER.info("进入拦截器");

        String url = exchange.getRequest().getURI().getPath();
        // 跳过不需要验证的路径
        if (isSkipUrl(url)) {
            LOGGER.info("跳过不需要验证的路径:{}", url);
            return chain.filter(exchange);
        }

        ServerHttpResponse response = exchange.getResponse();
        // 从请求头中取得token
        String token = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        // token是否为空
        if ( isNull(token) || "".equals(token.trim()) ) {
            return fail(response, "token不合法");
        }

        Object tokenObj = redisTemplate.opsForValue().get(token);
        if (tokenObj == null) {
            return fail(response, "身份认证失败");
        }

        //向请求参数中追加标识Id
        ServerWebExchange serverWebExchange = addRequestParamUserId(exchange, chain, String.valueOf(tokenObj));

        LOGGER.info("登录拦截器放行");
        //如果各种判断都通过，执行chain上的其他业务逻辑
        return chain.filter(serverWebExchange);
    }

    private Mono<Void> fail(ServerHttpResponse response, String message) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

        Map res = new ConcurrentHashMap();
        res.put("code", HttpStatus.UNAUTHORIZED.value());
        res.put("msg", HttpStatus.UNAUTHORIZED.getReasonPhrase());
        res.put("data", message);
        String result = JSONObject.toJSONString(res);

        DataBuffer buffer = response.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Flux.just(buffer));
    }


    /**
     * 判断当前访问的url是否开头URI是在配置的忽略url列表中
     *
     * @param url
     * @return
     */
    public boolean isSkipUrl(String url) {
        for (String skipAuthUrl : skipAuthUrls) {
            if (url.startsWith(skipAuthUrl)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }


    /**
     * 请求中添加参数
     */
    private ServerWebExchange addRequestParamUserId(ServerWebExchange exchange, GatewayFilterChain chain, String currentUserId) {
        ServerHttpRequest request = exchange.getRequest();
        String method = request.getMethodValue();

        if (HttpMethod.GET.matches(method)) {
            // 创建一个新的MultiValueMap并复制原始查询参数
            MultiValueMap<String, String> modifiedQueryParams = new LinkedMultiValueMap<>();

            // 添加要追加的参数
            modifiedQueryParams.add(ID, currentUserId);

            URI modifiedUri = UriComponentsBuilder.fromUri(request.getURI())
                    .queryParams(modifiedQueryParams)
                    .build()
                    .toUri();

            ServerHttpRequest modifiedRequest = request.mutate()
                    .uri(modifiedUri)
                    .build();

            return exchange.mutate().request(modifiedRequest).build();
        } else if (HttpMethod.POST.matches(method)) {
            // 处理POST请求
            Flux<DataBuffer> requestBody = request.getBody();


            // 添加要追加的参数
            Flux<DataBuffer> modifiedRequestBody = addBodyParameters(exchange, requestBody, currentUserId);

            // 创建一个新的ServerHttpRequestDecorator来包装原始请求，并修改请求体
            ServerHttpRequest modifiedRequest = new ServerHttpRequestDecorator(request) {
                @Override
                public Flux<DataBuffer> getBody() {
                    return modifiedRequestBody;
                }

//                @Override
//                public Flux<DataBuffer> getBody() {
//                    Flux<DataBuffer> body = modifiedRequestBody;
//                    return body.buffer().map(dataBuffers -> {
//                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
//                        DataBuffer join = dataBufferFactory.join(dataBuffers);
//                        byte[] content = new byte[join.readableByteCount()];
//                        join.read(content);
//                        DataBufferUtils.release(join);
//                        String bodyStr = new String(content, StandardCharsets.UTF_8);
//                        // 转成字节
//                        byte[] bytes = bodyStr.getBytes();
//                        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
//                        DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
//                        buffer.write(bytes);
//                        return buffer;
//                    });
//                }

                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders headers = new HttpHeaders();
                    headers.putAll(request.getHeaders());
                    headers.remove(HttpHeaders.CONTENT_LENGTH); // 移除Content-Length
                    if (!headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) {
                        headers.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); // 设置Transfer-Encoding为chunked
                    }
                    return headers;
                }

                @Override
                public URI getURI() {
                    return request.getURI();
                }

            };

            return exchange.mutate().request(modifiedRequest).build();
        }

        return exchange;
    }

    /**
     * post请求添加参数
     */
    private Flux<DataBuffer> addBodyParameters(ServerWebExchange exchange, Flux<DataBuffer> requestBody, String userId) {
        return requestBody.map(dataBuffer -> {
            // 解析原始请求体的JSON数据
            byte[] contentBytes = new byte[dataBuffer.readableByteCount()];
            dataBuffer.read(contentBytes);
            String requestBodyStr = new String(contentBytes, StandardCharsets.UTF_8);
//            String requestBodyD = StringEscapeUtils.unescapeJavaScript(requestBodyStr); //把反斜杠给替换掉了
            // 处理修改请求体的逻辑，例如添加要追加的参数
            JSONObject json = JSONObject.parseObject(requestBodyStr);
            json.put(ID, userId);

            // 将修改后的JSON数据转换为DataBuffer
            byte[] modifiedBytes = JSONObject.toJSONString(json).getBytes(StandardCharsets.UTF_8);

            DataBuffer modifiedDataBuffer = exchange.getResponse().bufferFactory().wrap(modifiedBytes);
            return modifiedDataBuffer;
        });
    }

}
